
#include "Self_Define_Functions.h"

// create new object of class for different functions
Benchmarks* generateFuncObj(int funcID)
{
	Benchmarks *fp;
	// run each of specified function in "configure.ini"
	if (funcID==1){
		fp = new F1();
	}else if (funcID==2){
		fp = new F2();
	}else if (funcID==3){
		fp = new F3();
	}else if (funcID==4){
		fp = new F4();
	}else if (funcID==5){
		fp = new F5();
	}else if (funcID==6){
		fp = new F6();
	}else if (funcID==7){
		fp = new F7();
	}else if (funcID==8){
		fp = new F8();
	}else if (funcID==9){
		fp = new F9();
	}else if (funcID==10){
		fp = new F10();
	}else if (funcID==11){
		fp = new F11();
	}else if (funcID==12){
		fp = new F12();
	}else if (funcID==13){
		fp = new F13();
	}else if (funcID==14){
		fp = new F14();
	}else if (funcID==15){
		fp = new F15();
	}else{
		cerr<<"Fail to locate Specified Function Index"<<endl;
		exit(-1);
	}
	return fp;
}



bool Compare_NewType( NewType data1, NewType data2 )
{
    return data1.data < data2.data;
}

double Distance( double *individual1, double *individual2, int dim )
{
    int i;
    double dis = 0;
    for( i = 0; i < dim; ++i )
    {
        dis += pow( individual1[i] - individual2[i], 2);
    }

    return sqrt( dis );
}

void Update_Pool_Nearest( double *insert_gbest, double result, double **pool, double *pool_results, int pool_size, int dim )
{

    double temp_dist;

    int i;

    double min_dist = Distance( insert_gbest, pool[0], dim );
    int min_index = 0;

    for( i = 1; i < pool_size; ++i )
    {
        temp_dist = Distance( insert_gbest, pool[i], dim );
        if( temp_dist <= min_dist )
        {
            min_dist = temp_dist;
            min_index = i;
        }
    }

    if( result < pool_results[min_index] )
    {
        pool_results[min_index] = result;
        memcpy( pool[min_index], insert_gbest, sizeof(double)*dim );
    }
}

void Update_Pool_Random( double *insert_gbest, double result, double **pool, double *pool_results, int pool_size, int dim )
{

    boost::mt19937 generator(time(0)*rand());
    boost::uniform_int<> uniform_int_generator( 0, pool_size-1 );
    boost::variate_generator< boost::mt19937&, boost::uniform_int<> > uniform_int_number( generator, uniform_int_generator );

    int selected_candidate;

    selected_candidate = uniform_int_number();

    if( result < pool_results[selected_candidate] )
    {
        pool_results[selected_candidate] = result;
        memcpy( pool[selected_candidate], insert_gbest, sizeof(double)*dim );
    }
}


void Update_Pool_Random_K_Nearest( double *insert_gbest, double result, double **pool, double *pool_results, int pool_size, int dim, int K )
{

    double temp_dist;

    int i;

    int *selected_candidate = new int[K];
    bool *flag_selected = new bool[pool_size];

    boost::mt19937 generator(time(0)*rand());
    boost::uniform_int<> uniform_int_generator( 0, pool_size-1 );
    boost::variate_generator< boost::mt19937&, boost::uniform_int<> > uniform_int_number( generator, uniform_int_generator );


    for( i = 0; i < pool_size; ++i )
    {
        flag_selected[i] = false;
    }

    for( i = 0; i < K; ++i )
    {
        do
        {
            selected_candidate[i] = uniform_int_number();
        }while( flag_selected[selected_candidate[i]] );

        flag_selected[selected_candidate[i]] = true;
    }

    double min_dist = Distance( insert_gbest, pool[selected_candidate[0]], dim );
    int min_index = selected_candidate[0];

    for( i = 1; i < K; ++i )
    {
        temp_dist = Distance( insert_gbest, pool[selected_candidate[i]], dim );
        if( temp_dist <= min_dist )
        {
            min_dist = temp_dist;
            min_index = selected_candidate[i];
        }
    }

    if( result < pool_results[min_index] )
    {
        pool_results[min_index] = result;
        memcpy( pool[min_index], insert_gbest, sizeof(double)*dim );
    }

    delete []selected_candidate;
    delete []flag_selected;
}





void Get_Elites( int *elites, int *non_elites, int elite_num, int non_elite_num, double *population_results, int population_size )
{
    int i;

    NewType *temp = new NewType[population_size];

    for( i = 0; i < population_size; ++i )
    {
        temp[i].data = population_results[i];
        temp[i].id = i;
    }

    sort( temp, temp+population_size, Compare_NewType );

    for( i = 0; i < elite_num; ++i )
        elites[i] = temp[i].id;

    for( i = 0; i < non_elite_num; ++i )
    {
        non_elites[i] = temp[i+elite_num].id;
    }

    delete []temp;
}


void Elite_Mean( double *elite_mean, int *elites, double **population, int elite_num, int dim )
{
    int i,j;

    for( i = 0; i < dim; ++i )
    {
        elite_mean[i] = 0;
    }

    for( i = 0; i < dim; ++i )
    {
        for( j = 0; j < elite_num; ++j )
        {
            elite_mean[i] += population[elites[j]][i];
        }

        elite_mean[i] /= elite_num;

    }
}

void Population_Mean( double *population_mean, double **population, int population_size, int dim )
{

    int i,j;


    for( i = 0; i < dim; ++i )
    {
        population_mean[i] = 0;
    }

    for( i = 0; i < dim; ++i )
    {
        for( j = 0; j < population_size; ++j )
        {
            population_mean[i] += population[j][i];
        }

        population_mean[i] /= population_size;

    }
}


void Individual_Update( double *position, double *speed, double *exemplar1, double *exemplar2, double *Lower_Bound, double *Upper_Bound, int dim, double phi )
{
    int i;

    boost::mt19937 generator(time(0)*rand());
    boost::uniform_real<> uniform_generator( 0, 1 );
    boost::variate_generator< boost::mt19937&, boost::uniform_real<> > uniform_number( generator, uniform_generator );

    for( i = 0; i < dim; ++i )
    {

        speed[i] = uniform_number() * speed[i] + uniform_number() * ( exemplar1[i] - position[i] ) + phi * uniform_number() * ( exemplar2[i] - position[i] );

        position[i] = position[i] + speed[i];

        if( position[i] < Lower_Bound[i] )
            position[i] = Lower_Bound[i];

        if( position[i] > Upper_Bound[i] )
            position[i] = Upper_Bound[i];

    }

}

//return how many elements are overlapped in the two sets;
int Intersection( int *last_elites, int *current_elites, int elite_num )
{
    int i;
    int counter = 0;
    map<int, int> result;
    for( i=0; i<elite_num;++i )
        result[ current_elites[i] ]++;
    for( i=0; i<elite_num; i++ )
        result[ last_elites[i] ]++;

    map<int, int>::iterator iter;
    for( iter=result.begin(); iter!=result.end(); iter++ )
        if(2 == iter->second)
            counter++;

    return counter;
}


void Selected_Candidates_Random( double *buffer, int candidate_num, double **population, double *population_results, int population_size, int dim )
{
    int i;

    boost::mt19937 generator(time(0)*rand());
    boost::uniform_int<> uniform_int_generator( 0, population_size-1 );
    boost::variate_generator< boost::mt19937&, boost::uniform_int<> > uniform_int_number( generator, uniform_int_generator );

    int selected_candiate;

    bool *population_selection = new bool[population_size];

    for( i = 0; i < population_size; ++i )
        population_selection[i] = false;


    for( i = 0; i < candidate_num; ++i )
    {
        do
        {
            selected_candiate = uniform_int_number();
        }while( population_selection[selected_candiate] );


        population_selection[selected_candiate] = true;
        memcpy( (buffer+i*(dim+1)), population[selected_candiate], sizeof(double)*dim );
        memcpy( (buffer+i*(dim+1)+dim), &population_results[selected_candiate], sizeof(double)*1 );

    }

    delete []population_selection;

}


void Selected_Candidates_Random_Index( int *candiate_index, int candidate_num, int population_size )
{
    int i;

    boost::mt19937 generator(time(0)*rand());
    boost::uniform_int<> uniform_int_generator( 0, population_size-1 );
    boost::variate_generator< boost::mt19937&, boost::uniform_int<> > uniform_int_number( generator, uniform_int_generator );


    bool *population_selection = new bool[population_size];

    for( i = 0; i < population_size; ++i )
        population_selection[i] = false;


    for( i = 0; i < candidate_num; ++i )
    {

        do
        {
            candiate_index[i] = uniform_int_number();
        }while ( population_selection[candiate_index[i]] );

        population_selection[candiate_index[i]] = true;

    }

    delete []population_selection;
}

void Compute_Probability( double *probability, double *population_result, int population_size )
{
    int i;

    probability[0] = population_result[0];

    for( i = 1; i < population_size; ++i )
    {
        probability[i] = probability[i-1] + population_result[i];
    }

    for( i = 0; i < population_size; ++i )
    {
        probability[i] /= probability[population_size-1];
    }
}

int Roulette_Wheel_Selection( double *probability, double random_probability, int probability_size )
{
    int i;

    if( random_probability <= probability[0] )
        return 0;
    else
    {
        for( i = 1; i < probability_size; ++i )
        {
            if( random_probability > probability[i-1] && random_probability <= probability[i] )
                return i;
        }
    }
}

void Selected_Candidates_Roulette( double *buffer, int candidate_num, double **population, double *population_results, int population_size, int dim )
{
    int i;

    boost::mt19937 generator(time(0)*rand());
    boost::uniform_real<> uniform_generator( 0, 1 );
    boost::variate_generator< boost::mt19937&, boost::uniform_real<> > uniform_number( generator, uniform_generator );

    int selected_candiate;
    double random_probability;

    double *probability = new double[population_size];

    bool *population_selection = new bool[population_size];

    for( i = 0; i < population_size; ++i )
        population_selection[i] = false;



    Compute_Probability( probability, population_results, population_size );


    for( i = 0; i < candidate_num; ++i )
    {

        do
        {
            random_probability = uniform_number();

            selected_candiate = Roulette_Wheel_Selection( probability, random_probability, population_size );
        }while( population_selection[selected_candiate] );


        population_selection[selected_candiate] = true;
        memcpy( (buffer+i*(dim+1)), population[selected_candiate], sizeof(double)*dim );
        memcpy( (buffer+i*(dim+1)+dim), &population_results[selected_candiate], sizeof(double)*1 );


    }

    delete []probability;
    delete []population_selection;

}


void Selected_Candidates_Roulette_Index( int *candidate_index, int candidate_num,  double *population_results, int population_size )
{
    int i;

    boost::mt19937 generator(time(0)*rand());
    boost::uniform_real<> uniform_generator( 0, 1 );
    boost::variate_generator< boost::mt19937&, boost::uniform_real<> > uniform_number( generator, uniform_generator );

    int selected_candiate;
    double random_probability;

    double *probability = new double[population_size];

    bool *population_selection = new bool[population_size];

    for( i = 0; i < population_size; ++i )
        population_selection[i] = false;



    Compute_Probability( probability, population_results, population_size );


    for( i = 0; i < candidate_num; ++i )
    {
        do
        {
            random_probability = uniform_number();

            selected_candiate = Roulette_Wheel_Selection( probability, random_probability, population_size );

        }while( population_selection[selected_candiate] );

        population_selection[selected_candiate] = true;
        candidate_index[i] = selected_candiate;

    }

    delete []probability;
    delete []population_selection;

}


void Compute_Elite_Probability( double *probability, int *elites, double *population_result, int elite_num )
{
    int i;

    probability[0] = population_result[elites[0]];

    for( i = 1; i < elite_num; ++i )
    {
        probability[i] = probability[i-1] + population_result[elites[i]];
    }

    for( i = 0; i < elite_num; ++i )
    {
        probability[i] /= probability[elite_num-1];
    }
}




void Compute_Elite_Candidate_Probability( double *probability, int *elite, double *population_result, int *candidate, double *pool_results, int elite_num, int candidate_num )
{

    int i;
    probability[0] = population_result[elite[0]];

    for( i = 1; i < elite_num; ++i )
    {
        probability[i] = probability[i-1] + population_result[elite[i]];
    }

    for( i = 0; i < candidate_num; ++i )
    {
        probability[i+elite_num] = probability[i+elite_num-1] + pool_results[candidate[i]];
    }

    for( i = 0; i < elite_num+candidate_num; ++i )
    {
        probability[i] /= probability[elite_num+candidate_num-1];
    }

}


void Compute_Elite_Candidate_Probability_Parallel( double *probability, int *elites, double *population_results, double *buffer, int elite_num,  int candidate_num, int dim )
{
    int i;
    probability[0] = population_results[elites[0]];

    for( i = 1; i < elite_num; ++i )
    {
        probability[i] = probability[i-1] + population_results[elites[i]];
    }


    for( i = 0; i < candidate_num; ++i )
    {
        probability[i+elite_num] = probability[i+elite_num-1] + buffer[i*(dim+1)+dim];
    }

    for( i = 0; i < elite_num+candidate_num; ++i )
    {
        probability[i] /= probability[elite_num+candidate_num-1];
    }

}






